﻿#region File Description
//-----------------------------------------------------------------------------
// ScopedTimer
//
// Copyright © 2013 Wave Coorporation. All rights reserved.
// Use is subject to license terms.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using WaveEngine.Framework;
using WaveEngine.Framework.Services;
#endregion

namespace WaveEngine.Extensions
{
    public class ScopedTimer
    {
        Timer internalTimer;
        Scene scene;

        private Action<ScopedTimer> internalAction;
        private Action wrapperAction;

        private string name;

        // Summary:
        //     The action to execute when the interval time passes.
        public Action<ScopedTimer> Action
        {
            get
            {
                return internalAction;
            }
            set
            {
                createWrapperAction(value);
                internalTimer.Action = wrapperAction;
            }
        }

        /// <summary>
        /// Creates the wrapper action.
        /// </summary>
        /// <param name="value">The value.</param>
        private void createWrapperAction(Action<ScopedTimer> value)
        {
            this.internalAction = value;
            this.wrapperAction = () =>
            {
                if (!this.scene.IsDisposed)
                {
                    this.internalAction(this);

                    if (!this.Looped)
                    {
                        // TimerFactory will delete the internalTimer, so we notify to subscribers.
                        this.OnDeleted();
                    }
                }
            };
        }

        //
        // Summary:
        //     Initial firing interval of this instance.
        public TimeSpan InitialInterval
        {
            get { return internalTimer.InitialInterval; }
            set { internalTimer.InitialInterval = value; }
        }

        //
        // Summary:
        //     The time that has passed in this current interval. It is reset to WaveEngine.Framework.Services.Timer.InitialInterval
        //     when it reaches zero unless WaveEngine.Framework.Services.Timer.Looped is
        //     set to true.
        public TimeSpan Interval
        {
            get { return internalTimer.Interval; }
        }

        //
        // Summary:
        //     Whether this instance will fire its action once, or more times.
        public bool Looped
        {
            get { return internalTimer.Looped; }
            set { internalTimer.Looped = value; }
        }
        //
        // Summary:
        //     The marked to delete.
        public bool MarkedToDelete
        {
            get { return this.internalTimer.MarkedToDelete; }
            private set { this.internalTimer.MarkedToDelete = value; }
        }

        // 
        // Sumary:
        //      The marked to paused
        public bool IsPaused
        {
            get { return this.internalTimer.IsPaused; }
            set { this.internalTimer.IsPaused = value; }
        }

        //
        // Summary:
        //     Name of this instance.
        public string Name
        {
            get { return this.name; }
            private set { this.name = value; }
        }

        public event EventHandler Deleted;

        /// <summary>
        /// Initializes a new instance of the <see cref="ScopedTimer" /> class.
        /// </summary>
        /// <param name="scene">The scene.</param>
        public ScopedTimer(Scene scene)
        {

        }

        public ScopedTimer(Scene scopedScene, string name, TimeSpan interval, Action<ScopedTimer> action, bool looped)
        {
            this.scene = scopedScene;
            this.Name = name;
            this.Update(interval, action, looped);

        }

        /// <summary>
        /// Deletes this instance.
        /// </summary>
        public void Delete()
        {
            WaveServices.TimerFactory.RemoveTimer(this.Name);

            this.OnDeleted();
        }

        /// <summary>
        /// Restarts the count.
        /// </summary>
        public void RestartCount()
        {
            this.internalTimer = WaveServices.TimerFactory.CreateTimer(this.Name,this.InitialInterval, this.wrapperAction, this.Looped);
            this.internalTimer.InitialInterval = this.InitialInterval;
        }

        /// <summary>
        /// Updates the the time with the new values.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="interval">The interval.</param>
        /// <param name="action">The action.</param>
        /// <param name="looped">if set to <c>true</c> [looped].</param>
        public void Update(TimeSpan interval, Action<ScopedTimer> action, bool looped)
        {
            this.createWrapperAction(action);
            this.internalTimer = WaveServices.TimerFactory.CreateTimer(this.Name, interval, this.wrapperAction, looped);
            this.internalTimer.InitialInterval = interval;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            return (obj is ScopedTimer) && ((ScopedTimer)obj).internalTimer == this.internalTimer;
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Called when [deleted].
        /// </summary>
        private void OnDeleted()
        {
            if (this.Deleted != null)
                this.Deleted(this, new EventArgs());
        }
    }
}
